package com.xiaoq.oauth2.service;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;

import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import com.xiaoq.JWTProperties;
import com.xiaoq.coms.RestException;
import com.xiaoq.oauth2.entity.OAuth2TokenEntity;
import com.xiaoq.oauth2.thirdpartclient.entity.Client;
import com.xiaoq.oauth2.thirdpartclient.service.ClientService;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Service
public class OAuth2Service {

	private static Logger logger = LoggerFactory.getLogger(OAuth2Service.class);

	private Cache cache;

	@Autowired
	private ClientService clientService;

	// @Autowired
	// private AccountService4dubbox accountService4dubbox;

	@Resource
	private JWTProperties jwtProperties;

	@Autowired
	public OAuth2Service(CacheManager cacheManager) {
		this.cache = cacheManager.getCache("oauth2-cache");
	}

	private void addAuthCode(String authCode, String username) {
		cache.put(authCode, username);
	}

	public void addAccessToken(String accessToken, String username) {
		cache.put(accessToken, username);
	}

	public boolean checkClientKey(String clientId) {
		return clientService.findByClientKey(clientId) != null;
	}

	public boolean checkClientSecret(String clientId, String clientSecret) {
		Client client = clientService.findByClientKey(clientId);
		return clientSecret.equals(client.getClientSecret());
	}

	public boolean checkClientSecret(Client client, String clientSecret) {
		return clientSecret.equals(client.getClientSecret());
	}

	public OAuth2TokenEntity getAccessTokenAndRereshToken4ThirdAPP(String authoCode, String userId, String signingKey,
			int durationPeriod) {

		// 生成token
		final String accessToken = createAccessToken(userId, signingKey, durationPeriod);
		logger.info("getAccessTokenAndRereshToken4ThirdAPP : " + accessToken);

		String refreshToken = createRefreshToken(userId, signingKey, durationPeriod);
		cache.put(refreshToken, accessToken);
		logger.info("accessToken : " + accessToken + "  refreshToken: " + refreshToken);
		// 清除授权码 确保一个code只能使用一次
		cache.evict(authoCode);

		// 构建oauth2授权返回信息
		OAuth2TokenEntity oAuth2_TokenEntity = new OAuth2TokenEntity();
		oAuth2_TokenEntity.setAccessToken(accessToken);
		oAuth2_TokenEntity.setRefreshToken(refreshToken);
		return oAuth2_TokenEntity;

	}

	public OAuth2TokenEntity getAccessTokenAndRefreshToken4XiaoqAPP(String userId, String signingKey,
			int durationPeriod) {
		// 生成token
		String accessToken = createAccessToken(userId, signingKey, durationPeriod);

		String refreshToken = createRefreshToken(userId, signingKey, durationPeriod * 6);
		// cache.put(accessToken,cache.get(authzCode).get());
		cache.put(refreshToken, accessToken);

		// 构建oauth2授权返回信息

		OAuth2TokenEntity oAuth2_TokenEntity = new OAuth2TokenEntity();
		oAuth2_TokenEntity.setAccessToken(accessToken);
		oAuth2_TokenEntity.setRefreshToken(refreshToken);
		return oAuth2_TokenEntity;

	}
	
	public OAuth2TokenEntity getAnonymousAccessTokenAndRefreshToken4XiaoqAPP(String userId, String signingKey,
			int durationPeriod) {
		// 生成token
		String accessToken = createAnonymousAccessToken(userId, signingKey, durationPeriod);

		String refreshToken = createAnonymousRefreshToken(userId, signingKey, durationPeriod * 6);
		// cache.put(accessToken,cache.get(authzCode).get());
		cache.put(refreshToken, accessToken);

		// 构建oauth2授权返回信息

		OAuth2TokenEntity oAuth2_TokenEntity = new OAuth2TokenEntity();
		oAuth2_TokenEntity.setAccessToken(accessToken);
		oAuth2_TokenEntity.setRefreshToken(refreshToken);
		return oAuth2_TokenEntity;

	}

	private String createAnonymousAccessToken(String userId, String signingKey, int durationPeriod) {

		Date expiryDate = getExpiryDate(durationPeriod * 24 * 60);// durationPeriod天的有效日期 24*60

		Map<String, Object> userMap = new HashMap<String, Object>();
		userMap.put("userId", userId);
		userMap.put("role", "anonymous");

		logger.info("......expiryDate = " + expiryDate.toString());

		logger.info("......new Date() = " + new Date().toString());

		String token = Jwts.builder().setClaims(userMap)//.setIssuer("DHC HUISHEGHUO Information Technology Co.Ltd")// 设置发行人
				//.setIssuedAt(new Date()) // 设置签发时间
				//.setSubject("lifeStyle365_users") // 设置面向的用户
				.setExpiration(expiryDate) // 设置过期时间
				.signWith(SignatureAlgorithm.HS256, signingKey).compact();
		logger.info("....... token = " + token);
		return token;
	}
	
	private String createAccessToken(String userId, String signingKey, int durationPeriod) {

		Date expiryDate = getExpiryDate(durationPeriod * 24 * 60);// durationPeriod天的有效日期 24*60

		Map<String, Object> userMap = new HashMap<String, Object>();
		userMap.put("userId", userId);
		userMap.put("role", "user");

		logger.info("......expiryDate = " + expiryDate.toString());

		logger.info("......new Date() = " + new Date().toString());

		String token = Jwts.builder().setClaims(userMap)//.setIssuer("DHC HUISHEGHUO Information Technology Co.Ltd")// 设置发行人
				//.setIssuedAt(new Date()) // 设置签发时间
				//.setSubject("lifeStyle365_users") // 设置面向的用户
				.setExpiration(expiryDate) // 设置过期时间
				.signWith(SignatureAlgorithm.HS256, signingKey).compact();
		logger.info("....... token = " + token);
		return token;
	}

	public String createAccessToken4clientCredentials(String clientId, String signingKey, int durationPeriod) {

		Date expiryDate = getExpiryDate(durationPeriod * 24 * 60);// durationPeriod天的有效日期

		Map<String, Object> userMap = new HashMap<String, Object>();
		userMap.put("clientId", clientId);

		return Jwts.builder().setClaims(userMap)//.setIssuer("DHC HUISHEGHUO Information Technology Co.Ltd")// 设置发行人
				//.setIssuedAt(new Date()) // 设置签发时间
				//.setSubject("lifeStyle365_users") // 设置面向的用户
				.setExpiration(expiryDate) // 设置过期时间
				.signWith(SignatureAlgorithm.HS256, signingKey).compact();
	}

	private String createRefreshToken(String userId, String signingKey, int durationPeriod) {

		Date expiryDate = getExpiryDate(durationPeriod * 24 * 60);// durationPeriod天的有效日期

		Map<String, Object> userMap = new HashMap<String, Object>();
		userMap.put("userId", userId);
		userMap.put("role", "user");

		return Jwts.builder().setClaims(userMap)//.setIssuer("DHC HUISHEGHUO Information Technology Co.Ltd")// 设置发行人
				//.setSubject("lifeStyle365_users") // 设置主题
				//.setIssuedAt(new Date()) // 设置签发时间
				.setExpiration(expiryDate) // 设置过期时间
				.signWith(SignatureAlgorithm.HS256, signingKey).compact();

	}

	private String createAnonymousRefreshToken(String userId, String signingKey, int durationPeriod) {

		Date expiryDate = getExpiryDate(durationPeriod * 24 * 60);// durationPeriod天的有效日期

		Map<String, Object> userMap = new HashMap<String, Object>();
		userMap.put("userId", userId);
		userMap.put("role", "anonymous");
		return Jwts.builder().setClaims(userMap)//.setIssuer("DHC HUISHEGHUO Information Technology Co.Ltd")// 设置发行人
				//.setSubject("lifeStyle365_users") // 设置主题
				//.setIssuedAt(new Date()) // 设置签发时间
				.setExpiration(expiryDate) // 设置过期时间
				.signWith(SignatureAlgorithm.HS256, signingKey).compact();

	}
	public String createRefreshToken4clientCredentials(String clientId, String signingKey, int durationPeriod) {

		Date expiryDate = getExpiryDate(durationPeriod * 24 * 60);// durationPeriod天的有效日期

		Map<String, Object> userMap = new HashMap<String, Object>();
		userMap.put("clientId", clientId);

		return Jwts.builder().setClaims(userMap)//.setIssuer("DHC HUISHEGHUO Information Technology Co.Ltd")// 设置发行人
				//.setIssuedAt(new Date()) // 设置签发时间
				//.setSubject("lifeStyle365_users") // 设置面向的用户
				.setExpiration(expiryDate) // 设置过期时间
				.signWith(SignatureAlgorithm.HS256, signingKey).compact();
	}

	private Date getExpiryDate(int minutes) {

		// 根据当前日期，来得到到期日期
		Calendar calendar = Calendar.getInstance();

		calendar.setTime(new Date());
		calendar.add(Calendar.MINUTE, minutes);

		return calendar.getTime();
	}

	public String loginAndGenerateAuthCode(String loginName, String password, String currentLoginIp,
			String responseType) throws OAuthSystemException {
		/*
		 * //基于dubbox调用AccountService的login接口 AccountDTO accountDTO =
		 * accountService4dubbox.login(loginName, password,currentLoginIp);
		 * 
		 * if (accountDTO == null) throw new RuntimeException("user [" + loginName +
		 * "] invokeLogin failed");
		 * 
		 * //非dubbo消费端,通过restful API的方式调用dubbox中提供的login接口（todo://与上面的dubbo协议的接口二选一即可）
		 * // invokeLogin("http://127.0.0.1:" + 9090 + "/api/v1/accounts/login/1/1");
		 * 
		 * //生成授权码 String authorizationCode = null; //responseType目前仅支持CODE，另外还有TOKEN if
		 * (responseType.equals(ResponseType.CODE.toString())) { OAuthIssuerImpl
		 * oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator()); authorizationCode
		 * = oauthIssuerImpl.authorizationCode(); logger.info("authorizationCode = " +
		 * authorizationCode); addAuthCode(authorizationCode, loginName); } return
		 * authorizationCode;
		 */
		return null;
	}

	private void invokeLogin(String url) {
		System.out.println("starting to invokeLogin via " + url);
		javax.ws.rs.client.Client client = ClientBuilder.newClient();
		WebTarget target = client.target(url);
		Response response = target.request().get();
		try {
			if (response.getStatus() != 200) {
				throw new RuntimeException("Failed with HTTP error code : " + response.getStatus());
			}
			System.out.println("Successfully got result: " + response.readEntity(String.class));
		} finally {
			response.close();
			client.close();
		}
	}

	public String parseUserIdFromAccessToken(String accessToken) {
		accessToken = accessToken.substring(7); // The part after "Bearer "
		try {
			final Claims claims = Jwts.parser().setSigningKey(jwtProperties.getSecretKey()).parseClaimsJws(accessToken)
					.getBody();
			return claims.get("userId").toString();

		} catch (ExpiredJwtException expEx) {// 如果access_token过期
			throw new RestException(HttpStatus.FORBIDDEN, "the token has been expired");
			// http://localhost:8080/oauth2/refresh_token?client_id={AppKey}&grant_type=refresh_token&refresh_token={refresh_token}
		} catch (final Exception e) {
			throw new RestException(e.getMessage());
		}
	}
}
